package com.smsc.headend.task.engine.handler.impl.deviceconfig;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.smsc.headend.common.enums.errorcode.TaskHandlerErrorCode;
import com.smsc.headend.common.utils.CosemUtils;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.common.AppName;
import com.smsc.headend.module.data.dto.DataItemDTO;
import com.smsc.headend.module.data.enums.OperationGroup;
import com.smsc.headend.module.data.enums.OperationName;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.protocol.cosem.bo.CosemData;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.mapper.ModuleUnitMapper;
import com.smsc.headend.task.engine.service.CosemXmlService;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import gurux.dlms.enums.DataType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;

/**
 * (业务实现)
 *
 * @author wjh
 * @date 2022/4/13 9:10.
 */
@Slf4j
public class ReadStepTariffHandler implements TaskHandler {

    @Autowired
    CosemXmlService cosemXmlService;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    AssetService assetService;
    @Autowired
    ModuleUnitMapper moduleUnitMapper;
    @Autowired
    FeignAssetManagementService assetManagementService;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData deviceData, String actionResult) throws UDISTaskHandlerException {
        if (!(deviceData instanceof CosemData)) {
            throw new UDISTaskHandlerException(TaskHandlerErrorCode.DEVICE_DATA_TYPE_NOT_SUPPORT.toString());
        }
        CosemData cosemData = (CosemData) deviceData;
        Map<String, Object> m = JSONUtil.toBean(atomicTask.getAtomicTaskParam(), Map.class);
        Object value = getData(cosemData, task, atomicTask);
        log.debug("read step tariff value {}", value);
        if (StrUtil.equalsIgnoreCase(task.getTaskType(), TaskType.Action_DeviceParamConfig_Get.name())) {
            Map<String, String> result = MapUtil.newHashMap();
            result.put("stDataGroup", Convert.toStr(m.get("stDataGroup")));
            result.put("seq", Convert.toStr(m.get("seq")));
            result.put("value", Convert.toStr(value));
            OperationName operationName = OperationName.forId(atomicTask.getOperationId());
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), operationName.getName(), result, 600L, true);
            if (isSubTaskGroupLastAtomicTask(task, atomicTask)) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), "subTaskCompleted", true, 600L, true);
            }
        }
        return 1;
    }

    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.info("error {}, ", message);
        if (atomicTask.getGroupId() == OperationGroup.StepTariffActiveDateGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StepTariffBackUpRatePriceGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StepTariffBackUpStepGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StPaymentControlConfigGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StFunctionControlConfigGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StepTariffActiveStepGet.getId().intValue()
                || atomicTask.getGroupId() == OperationGroup.StepTariffActiveRatePriceGet.getId().intValue()) {
            String operationGroupName = OperationGroup.forId(atomicTask.getGroupId().intValue()).getName();
            String stepOperationName = OperationName.forId(atomicTask.getOperationId()).getName();
            if (task.getIsODR()) {
                taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), stepOperationName, String.format("step %s failed, [%s]", operationGroupName, message), 3600l, false);
            }
        }
        return -1;
    }

    public Object getData(CosemData cosemData, Task task, AtomicTask atomicTask) {
        Object data = cosemXmlService.getData(cosemData.getType(), cosemData.getValue());
        if (DataType.OCTET_STRING.toString().equalsIgnoreCase(cosemData.getType())) {
            if (CosemUtils.isDateTimeString(Convert.toStr(data))) {
                data = DateFormatUtils.format(CosemUtils.parseOctStringDataTime(Convert.toStr(data)), "yyyy-MM-dd HH:mm:ss");
            } else if (CosemUtils.isLocalDate(Convert.toStr(data))) {
                data = CosemUtils.parseOctStringDate(Convert.toStr(data));
            } else if (CosemUtils.isLocalTime(Convert.toStr(data))) {
                data = CosemUtils.parseOctStringTime(Convert.toStr(data));
            } else if (CosemUtils.isAsciiHexStr(Convert.toStr(data))) {
                data = HexUtil.decodeHexStr(Convert.toStr(data));
            }
        }
        Meter meter = assetService.getMeterById(task.getMeterId());
        if (null != meter) {
            List<DataItemDTO> dataItemDTOS = assetManagementService.queryModelOperationDataItemCosem(meter.getModelId(), atomicTask.getGroupId(), atomicTask.getOperationId(), atomicTask.getSeq(), null);
            if (!CollectionUtils.isEmpty(dataItemDTOS)) {
                Long subDataItemId = dataItemDTOS.get(0).getSubDataItemId();
                data = assetManagementService.convertDataItemValueWithUnit(meter.getModelId(), subDataItemId, Convert.toStr(data), AppName.GUI.name());
            }
        }
        return data;
    }
}
